package com.rpc.proxy.impl.jdk;

import com.google.common.collect.Lists;
import com.rpc.client.ClientHandler;
import com.rpc.client.ConnectManager;
import com.rpc.client.RpcFuture;
import com.rpc.proxy.impl.InvokerProxy;
import com.rpc.transport.RequestData;
import com.rpc.transport.ResponseData;
import com.rpc.util.generationid.IGenerationID;
import com.rpc.util.generationid.UUIDIGenerationIDImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

/**
 * @author yanzhuoleo
 * @version V1.0
 * @Description: 代理实现类
 * @date 2017-12-28-下午5:34
 */

public class JdkInvokerInvocationHandler implements InvocationHandler, InvokerProxy {
    /**
     * TODO:使用spring优化
     */
    private IGenerationID generationID = new UUIDIGenerationIDImpl();

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //这里不处理服务器启动  应该直接获取一个handler 由handler获取数据

        if (Object.class == method.getDeclaringClass()) {
            String name = method.getName();
            if ("equals".equals(name)) {
                return proxy == args[0];
            } else if ("hashCode".equals(name)) {
                return System.identityHashCode(proxy);
            } else if ("toString".equals(name)) {
                return proxy.getClass().getName() + "@" +
                       Integer.toHexString(System.identityHashCode(proxy)) +
                       ", with InvocationHandler " + this;
            } else {
                throw new IllegalStateException(String.valueOf(method));
            }
        }

        RequestData requestData = new RequestData();
        requestData.setRequestId(generationID.getId());
        //获取实际调用类的名字 如果直接用proxy会获取到代理的名字
        requestData.setClassName(method.getDeclaringClass().getName());
        requestData.setMethodName(method.getName());
        List<Class> parameterTypes = Lists.newArrayListWithExpectedSize(args.length);
        for (int index = 0; index < args.length; ++index) {
            parameterTypes.add(args[index].getClass());
        }
        requestData.setParameterTypes(parameterTypes.toArray(new Class[args.length]));
        requestData.setArgs(args);

        ClientHandler clientHandler = ConnectManager.getClientHandler();
        RpcFuture     future        = clientHandler.sendRequest(requestData);
        //TODO: void类型是否要单独判断
        //TODO:这里使用Optional 避免NPE
        ResponseData responseData = future.get();
        if (responseData != null) {
            return responseData.getResponseData();
        }

        return null;
    }

    @Override
    public <T> T bind(Class<T> objectClass) {
        return (T) Proxy.newProxyInstance(objectClass.getClassLoader(), new Class<?>[]{objectClass},
                                          this);
    }
}
